Passed
Push — main ( 299d81...c6ed9c )
by Martin
59s queued 14s
created

emp.js ➔ comparePasswords   A

Complexity

Conditions 4

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 40
rs 9.256
c 0
b 0
f 0
cc 4
1
import bcrypt from "bcryptjs";
2
import jwt from "jsonwebtoken";
3
import { db } from "./db.js"
4
5
import dotenv from "dotenv";
6
dotenv.config();
7
8
import express from "express";
9
10
11
const jwtSecret = String(process.env.JWT_SECRET);
12
13
const emp = {
14
    /**
15
     * Returns id, username,
16
     * password-hash and role.
17
     * Will not return anything if
18
     * the admin's account has been
19
     * deactivated
20
     * @param {String} username 
21
     * @returns {Promise<Object>}
22
     */
23
    getOneFromDb: async function(username) {
24
        const result = await db.queryWithArgs(`CALL emp_login(?);`, [username]);
25
        return result[0][0];
26
    },
27
    /**
28
     * Checks if a token is valid
29
     * and if it's payload contains
30
     * role attribute with value
31
     * "admin"
32
     * @param {express.Request} req 
33
     * @param {express.Response} res 
34
     * @param {express.NextFunction} next 
35
     */
36
    checkAdminAcc: function(req, res, next) {
37
        this.checkToken(req, res, next, ["admin"]);
38
    },
39
    /**
40
     * Checks if a token is valid
41
     * and if it's payload contains
42
     * role attribute with a value
43
     * that is included in the array
44
     * of acceptable rows
45
     * @param {express.Request} req 
46
     * @param {express.Response} res 
47
     * @param {express.NextFunction} next 
48
     * @param {Array} acceptableRoles array with acceptable roles, for example ["admin"] or ["admin", "superadmin"]
49
     */
50
    checkToken: function(req, res, next, acceptableRoles) {
51
        let token = req.headers["x-access-token"];
52
53
        /**
54
         * @typedef {Object} JwtPayload
55
         * @property {String} role
56
         * @property {String} id
57
         */
58
        jwt.verify(token, jwtSecret, function (err, /** @type {JwtPayload} */decoded) {
59
            // if no token has been provided,
60
            // or if provided token is expired
61
            // this block will be executed
62
            if (err) {
63
                return res.status(500).json({
64
                    errors: {
65
                        status: 500,
66
                        source: "authorization",
67
                        title: "Failed authentication",
68
                        detail: err.message
69
                    }
70
                });
71
            }
72
73
            if (!acceptableRoles.includes(decoded.role)) {
74
                // if unauthorized request it is safer
75
                // to make it look like the page does not
76
                // exist
77
                return res.status(404).json({
78
                    errors: {
79
                        status: 404,
80
                        source: req.originalUrl,
81
                        title: "Not found",
82
                        detail: "Page not found"
83
                    }
84
                });
85
            }
86
            /**
87
             * OBS! osäker på om vi
88
             * behöver lägga till
89
             * dessa detaljer i bodyn,
90
             * jag tror inte att
91
             * det kommer behövas någonstans? 
92
             * Har admin  passerat denna route
93
             * så är det redan säkerställt att man har behörighet
94
             */
95
            req.body.emp = {
96
                id: decoded.id,
97
                role: decoded.role
98
            };
99
100
            return next();
101
        });
102
    },
103
104
    /**
105
     * @description Function that handles admin login
106
     *
107
     * @param {express.Request} req Request object
108
     * @param {express.Response} res Response object
109
     *
110
     * @returns {Promise<Object>} JSON object
111
     */
112
    login: async function (req, res) {
113
        const username = req.body.username;
114
        const password = req.body.password;
115
116
        const emp = await this.getOneFromDb(username);
117
118
        // om användarnamn saknas kommer
119
        // databasen lyfta ett error
120
        // om lösenord saknas kommer det fångas i bcrypt compare
121
122
        return this.comparePasswords(res, password, emp);
123
    },
124
125
    checkPassword: function(res, result, emp) {
126
        if (result) {
127
            const payload = {
128
                id: emp.id,
129
                role: emp.role
130
            };
131
            const jwtToken = jwt.sign(payload, jwtSecret, { expiresIn: "24h" });
132
133
            return res.json({
134
                data: {
135
                    type: "success",
136
                    message: "User logged in",
137
                    user: payload,
138
                    token: jwtToken
139
                }
140
            });
141
        }
142
143
        return res.status(401).json({
144
            errors: {
145
                status: 401,
146
                source: "/login",
147
                title: "Wrong password",
148
                detail: "Password is incorrect."
149
            }
150
        });
151
    },
152
    /**
153
     * @description Function that compares password to the hash
154
     * stored in db
155
     *
156
     * @param {express.Response} res Response object
157
     * @param {String} password Password
158
     * @param {Object} emp User
159
     *
160
     * @returns {Object} JSON object
161
     */
162
    comparePasswords: async function (res, password, emp) {
163
        try {
164
            const result = await bcrypt.compare(password, emp.hash);
165
            return this.checkPassword(res, result, emp);
166
        } catch (error) {
167
            return res.status(500).json({
168
                errors: {
169
                    status: 500,
170
                    source: "/login",
171
                    title: "bcrypt error",
172
                    detail: "bcrypt error"
173
                }
174
            });
175
        }
176
    }
177
};
178
179
export default emp;